package cloud.xiangyixiang.www.spring.boot.java.basics.controller;

import cloud.xiangyixiang.www.spring.boot.java.basics.classes.PersonStream;
import cloud.xiangyixiang.www.spring.boot.java.basics.classes.StaffStream;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * <p>
 * JAVA8 流处理
 * </p>
 *
 * @author zhixinglu
 * @date 2023/9/18 19:34
 */
public class StreamController {

    public static void main(String[] args) {
        StaffStream.initPerson();

        test1();

        test2();

        test3();

        test4();

        test5();

        test6();

        test7();

        test8();

        test9();

        test10();

        test11();

        test12();

        test13();

        test14();

        test15();

        test16();

        test17();

        test18();

        test19();

        test20();

        test21();

        test22();
    }

    /**
     *
     */
    private static void test1(){
        List<String> list = Arrays.asList("a", "b", "c");
        // 创建一个顺序流
        Stream<String> stream = list.stream();
        // 创建一个并行流
        Stream<String> parallelStream = list.parallelStream();
        System.out.println(Arrays.toString(stream.toArray()));
        System.out.println(Arrays.toString(parallelStream.toArray()));

        int[] array = {1, 3, 5, 6, 8};
        IntStream stream1 = Arrays.stream(array);
        System.out.println(Arrays.toString(stream1.toArray()));


        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6);
        stream2.forEach(System.out::print);
        System.out.println();

        Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 3).limit(4);
        stream3.forEach(System.out::println);
        System.out.println();

        Stream<Double> stream4 = Stream.generate(Math::random).limit(3);
        stream4.forEach(System.out::println);
        System.out.println();


        System.out.println();
    }

    /**
     * Stream 遍历/匹配（foreach/find/match）
     */
    private static void test2(){
        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);

        // 遍历输出符合条件的元素
        list.stream().filter(x -> x > 6).forEach(System.out::println);
        // 匹配第一个
        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        // 匹配任意（适用于并行流）
        Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
        // 是否包含符合特定条件的元素
        boolean anyMatch = list.stream().anyMatch(x -> x < 6);
        System.out.println("匹配第一个值：" + findFirst.get());
        System.out.println("匹配任意一个值：" + findAny.get());
        System.out.println("是否存在大于6的值：" + anyMatch);

        System.out.println();
    }

    /**
     * 筛选员工中未满18周岁的人，并形成新的集合
     * @思路
     * List<Person> list = new ArrayList<Person>();
     * for(Person person : personList) {
     *     if(person.getAge() > 18) {
     *          list.add(person);
     *     }
     * }
     */
    private static void test3(){
        List<PersonStream> personList = StaffStream.getPersonList();
        List<PersonStream> collect = personList.stream().filter(x -> x.getAge()>18).collect(Collectors.toList());
        System.out.println(collect);
        System.out.println();
    }

    /**
     *
     */
    private static void test4(){
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("id", 1);
        map1.put("name", "ZhangSan");
        map1.put("age", 18);
        list.add(map1);

        Map<String, Object> map2 = new HashMap<>();
        map2.put("id", 2);
        map2.put("name", "LiSi");
        map2.put("age", 19);
        list.add(map2);

        System.out.println("初始化List：" + list);

        streamTest(list);
        beforeJava8(list);

        System.out.println();
    }

    /**
     * Stream 获取张三数据
     * @param list {@link List<Map<String, Object>>}
     */
    private static void streamTest(List<Map<String, Object>> list){
        List<Map<String, Object>> collect = list.stream().filter(a -> a.get("name").toString().equals("ZhangSan")).collect(Collectors.toList());
        System.out.println("Java8: " + collect);
    }

    /**
     * Java8以前获取张三数据
     * @param list {@link List<Map<String, Object>>}
     */
    private static void beforeJava8(List<Map<String, Object>> list){
        List<Map<String, Object>> reList = new ArrayList<>();
        Map<String, Object> hashMap = new HashMap<>();
        for (Map<String, Object> map: list) {
            if (map.get("name").equals("ZhangSan")) {
                hashMap.putAll(map);
            }
        }
        reList.add(hashMap);
        System.out.println("beforeJava8: " + reList);
    }

    /**
     * 获取String集合中最长的元素
     * @思路
     * List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
     * String max = "";
     * int length = 0;
     * int tempLength = 0;
     * for(String str : list) {
     *     tempLength = str.length();
     *     if(tempLength > length) {
     *         length  = str.length();
     *         max = str;
     *      }
     * }
     * @return hangman
     */
    private static void test5(){
        List<String> list = Arrays.asList("hangman", "list", "wing", "sunlit");
        Comparator<? super String> comparator = Comparator.comparing(String::length);
        Optional<String> max = list.stream().max(comparator);
        System.out.println(max);
        System.out.println();
    }

    /**
     * 获取Integer集合中的最大值
     */
    private static void test6() {
        List<Integer> list = Arrays.asList(1, 17, 27, 7);
        Optional<Integer> max = list.stream().max(Integer::compareTo);
        // 自定义排序
        Optional<Integer> max2 = list.stream().max((o1, o2) -> o1.compareTo(o2));
        System.out.println(max2);
        System.out.println();
    }

    /**
     * 获取员工中年龄最大的人
     */
    private static void test7() {
        List<PersonStream> personList = StaffStream.getPersonList();
        Comparator<? super PersonStream> comparator = Comparator.comparingInt(PersonStream::getAge);
        Optional<PersonStream> max = personList.stream().max(comparator);
        System.out.println(max);
        System.out.println();
    }

    /**
     * 计算integer集合中大于10的元素的个数
     */
    private static void test8() {
        List<Integer> list = Arrays.asList(1, 17, 27, 7);
        long count = list.stream().filter(x -> x > 10).count();
        System.out.println(count);
        System.out.println();
    }

    /**
     * 字符串大写
     */
    private static void test9(){
        List<String> list = Arrays.asList("hangman", "list", "wing", "sunlit");
        list.stream().forEach(String::toUpperCase);
        List<String> collect = list.stream().map(String::toUpperCase).collect(Collectors.toList());
        System.out.println(list);
        System.out.println(collect);
        System.out.println();
    }

    /**
     * 整数数组每个元素+3
     * @思路
     * List<Integer> list = Arrays.asList(1, 17, 27, 7);
     * List<Integer> list2 = new ArrayList<Integer>()
     * for(Integer num : list) {
     *   list2.add(num + 3);
     * }
     * @return [4, 20, 30, 10]
     */
    private static void test10() {
        List<Integer> list = Arrays.asList(1, 17, 27, 7);
        List<Integer> collect = list.stream().map(x -> x + 3).collect(Collectors.toList());
        System.out.println(collect);
        System.out.println();
    }

    /**
     * 公司效益好，每人涨2000
     */
    private static void test11(){
        List<PersonStream> personList = StaffStream.getPersonList();
        System.out.println(personList);
        List<PersonStream> personList1 = personList.stream().map(x -> {x.setSalary(x.getSalary() + 2000); return x;}).collect(Collectors.toList());
        System.out.println(personList1);
        System.out.println();
    }

    /**
     * 将两个字符数组合并成一个新的字符数组
     * @return [z,  h,  a,  n,  g, s,  a,  n]
     */
    private static void test12() {
        String[] arr = {"z, h, a, n, g", "s, a, n"};
        List<String> list = Arrays.asList(arr);
        System.out.println(list);
        List<String> collect = list.stream().flatMap(x -> {
            String[] array = x.split(",");
            return Arrays.stream(array);
        }).collect(Collectors.toList());
        System.out.println(collect);
        System.out.println();
    }

    /**
     * 求Integer集合的元素之和、乘积和最大值
     *
     */
    private static void test13() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4);
        // 求和
        Optional<Integer> reduce = list.stream().reduce(Integer::sum);
        System.out.println("求和: " + reduce);
        // 求积
        Optional<Integer> reduce2 = list.stream().reduce((x,y) -> x * y);
        System.out.println("求积: " + reduce2);
        // 求最大值
        Optional<Integer> reduce3 = list.stream().reduce((x,y) -> x>y?x:y);
        System.out.println("求最大值: " + reduce3);

        System.out.println();
    }

    /**
     * 求所有员工的工资之和和最高工资
     */
    private static void test14() {
        List<PersonStream> personList = StaffStream.getPersonList();
        Optional<Integer> reduce = personList.stream().map(PersonStream :: getSalary).reduce(Integer::sum);
        Optional<Integer> reduce2 = personList.stream().map(PersonStream :: getSalary).reduce(Integer::max);
        System.out.println("工资之和: " + reduce);
        System.out.println("最高工资: " + reduce2);
        System.out.println();
    }

    /**
     * 取出大于18岁的员工转为map
     *
     */
    private static void test15() {
        List<PersonStream> personList = StaffStream.getPersonList();
        Map<String, PersonStream> collect = personList.stream()
                .filter(x -> x.getAge() > 18)
                .collect(Collectors.toMap(PersonStream::getName, y -> y, (existing, replacement) -> existing));
        System.out.println(collect);

        System.out.println();
    }

    /**
     * 统计员工人数、平均工资、工资总额、最高工资
     */
    private static void test16(){
        List<PersonStream> personList = StaffStream.getPersonList();
        //统计员工人数
        Long count = personList.stream().collect(Collectors.counting());
        //求平均工资
        Double average = personList.stream().collect(Collectors.averagingDouble(PersonStream::getSalary));
        //求最高工资
        Optional<Integer> max = personList.stream().map(PersonStream::getSalary).collect(Collectors.maxBy(Integer::compare));
        //求工资之和
        Integer sum = personList.stream().collect(Collectors.summingInt(PersonStream::getSalary));
        //一次性统计所有信息
        DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(PersonStream::getSalary));
        System.out.println("统计员工人数:"+count);
        System.out.println("求平均工资:"+average);
        System.out.println("求最高工资:"+max);
        System.out.println("求工资之和:"+sum);
        System.out.println("一次性统计所有信息:"+collect);
        System.out.println();
    }

    /**
     * 将员工按薪资是否高于8000分为两部分；将员工按性别和地区分组
     */
    private static void test17(){
        List<PersonStream> personList = StaffStream.getPersonList();
        personList.add(new PersonStream("ZhangSan",25, 3000, "male", "临汾"));
        personList.add(new PersonStream("LiSi",27, 5000, "male", "临汾"));
        personList.add(new PersonStream("WingWu",29, 7000, "female", "临汾"));
        personList.add(new PersonStream("SunLiu",26, 3000, "female", "运城"));
        personList.add(new PersonStream("YinQi",27, 5000, "male", "运城"));
        personList.add(new PersonStream("GuBa",21, 7000, "female", "运城"));


        // 将员工按薪资是否高于8000分组
        Map<Boolean, List<PersonStream>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
        // 将员工按性别分组
        Map<String, List<PersonStream>> group = personList.stream().collect(Collectors.groupingBy(PersonStream::getGender));
        // 将员工先按性别分组，再按地区分组
        Map<String, Map<String, List<PersonStream>>> group2 = personList.stream()
                .collect(Collectors.groupingBy(PersonStream::getGender, Collectors.groupingBy(PersonStream::getHome)));
        System.out.println("员工按薪资是否大于8000分组情况：" + part);
        System.out.println("员工按性别分组情况：" + group);
        System.out.println("员工按性别、地区：" + group2);
        System.out.println();
    }


    /**
     * 结合joining
     */
    private static void test18(){
        List<PersonStream> personList = StaffStream.getPersonList();
        String names = personList.stream().map(PersonStream::getName).collect(Collectors.joining(","));
        System.out.println(names);
        System.out.println();
    }

    /**
     * 排序sorted
     *
     *  将员工按工资由高到低（工资一样则按年龄由大到小）排序
     */
    private static void test19(){
        List<PersonStream> personList = StaffStream.getPersonList();
        // 按工资升序排序（自然排序）
        List<String> newList = personList.stream().sorted(Comparator.comparing(PersonStream::getSalary)).map(PersonStream::getName)
                .collect(Collectors.toList());
        // 按工资倒序排序
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(PersonStream::getSalary).reversed())
                .map(PersonStream::getName).collect(Collectors.toList());
        // 先按工资再按年龄升序排序
        List<String> newList3 = personList.stream()
                .sorted(Comparator.comparing(PersonStream::getSalary).thenComparing(PersonStream::getAge)).map(PersonStream::getName)
                .collect(Collectors.toList());
        // 先按工资再按年龄自定义排序（降序）
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                return p2.getSalary() - p1.getSalary();
            }
        }).map(PersonStream::getName).collect(Collectors.toList());

        System.out.println("按工资升序排序：" + newList);
        System.out.println("按工资降序排序：" + newList2);
        System.out.println("先按工资再按年龄升序排序：" + newList3);
        System.out.println("先按工资再按年龄自定义降序排序：" + newList4);
        System.out.println();
    }

    /**
     * 流也可以进行合并、去重、限制、跳过等操作。
     */
    private static void test20(){
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat:合并两个流 distinct：去重
        List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        // limit：限制从流中获得前n个数据
        List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
        // skip：跳过前n个数据
        List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());

        System.out.println("流合并：" + newList);
        System.out.println("limit：" + collect);
        System.out.println("skip：" + collect2);

        System.out.println();
    }

    /**
     * 读取文件操作
     */
    private static void test21(){
        String filePath = "/Users/weixin/workspace/IdeaProjects/spring-boot-learning/spring-boot-java-basics/src/main/resources/static/Class.txt";
        Path path = new File(filePath).toPath();
        try( Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8) ) {
            lines.onClose( () -> System.out.println("Done!")).forEach(System.out::println);
        } catch (IOException e) {
            System.out.println("stream file error: " + e.getMessage());
        }
        System.out.println();
    }

    /**
     * 计算两个list中的差集
     */
    private static void test22(){
        List<String> allList = new ArrayList<>(5);
        allList.add("class1");
        allList.add("class2");
        allList.add("class3");
        allList.add("class4");
        allList.add("class5");

        List<String> wList = new ArrayList<>(5);
        wList.add("class1");
        wList.add("class3");
        wList.add("class5");
        wList.add("class7");
        wList.add("class9");

        List<String> reduce1 = allList.stream().filter(item -> !wList.contains(item)).collect(Collectors.toList());
        System.out.println(reduce1);
        System.out.println();
    }
}
